#include "laurin-80211-frame.h"
#include "laurin-utils.h"
#include "laurin-IEEE80211.h"

#define FIXED_PARAMETERS_OFFSET 12

// ---------- from kismet source, copyright holds ----------/

typedef struct {
    u_int8_t timestamp[8];                                                                                                      // timestamp 8 bytes

    // This field must be converted to host-endian before being used
    unsigned int beacon : 16 __attribute__ ((packed));                                          // beacon interval 2 bytes

    unsigned short agility : 1 __attribute__ ((packed));                                        // channel agility
    unsigned short pbcc : 1 __attribute__ ((packed));                                           // pbcc modulation allowed?
    unsigned short short_preamble : 1 __attribute__ ((packed));                         // short preamble
    unsigned short wep : 1 __attribute__ ((packed));                                            // wep support

    unsigned short unused2 : 1 __attribute__ ((packed));
    unsigned short unused1 : 1 __attribute__ ((packed));
    unsigned short ibss : 1 __attribute__ ((packed));                                           // ibss participation
    unsigned short ess : 1 __attribute__ ((packed));                                            // ess capabilities

    unsigned int coordinator : 8 __attribute__ ((packed));

} fixed_parameters;


static u_int ieee80211_mhz2ieee(u_int freq, u_int flags) {
	if (flags & IEEE80211_CHAN_2GHZ) {              /* 2GHz band */
		if (freq == 2484)
			return 14;
		if (freq < 2484)
			return (freq - 2407) / 5;
		else
			return 15 + ((freq - 2512) / 20);
	} else if (flags & IEEE80211_CHAN_5GHZ) {       /* 5Ghz band */
		return (freq - 5000) / 5;
	} else {                                        /* either, guess */
		if (freq == 2484)
			return 14;
		if (freq < 2484)
			return (freq - 2407) / 5;
		if (freq < 5000)
			return 15 + ((freq - 2512) / 20);
		return (freq - 5000) / 5;
	}
}

#define IEEE80211_CHAN_FHSS             (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_GFSK)
#define IEEE80211_CHAN_A                (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM)
#define IEEE80211_CHAN_B                (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_CCK)
#define IEEE80211_CHAN_PUREG    (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_OFDM)
#define IEEE80211_CHAN_G                (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_DYN)
#define IEEE80211_CHAN_T                (IEEE80211_CHAN_5GHZ | IEEE80211_CHAN_OFDM | IEEE80211_CHAN_TURBO)

#define IEEE80211_IS_CHAN_FHSS(_flags)  ((_flags & IEEE80211_CHAN_FHSS) == IEEE80211_CHAN_FHSS)
#define IEEE80211_IS_CHAN_A(_flags)             ((_flags & IEEE80211_CHAN_A) == IEEE80211_CHAN_A)
#define IEEE80211_IS_CHAN_B(_flags)             ((_flags & IEEE80211_CHAN_B) == IEEE80211_CHAN_B)
#define IEEE80211_IS_CHAN_PUREG(_flags) ((_flags & IEEE80211_CHAN_PUREG) == IEEE80211_CHAN_PUREG)
#define IEEE80211_IS_CHAN_G(_flags)             ((_flags & IEEE80211_CHAN_G) == IEEE80211_CHAN_G)
#define IEEE80211_IS_CHAN_T(_flags)             ((_flags & IEEE80211_CHAN_T) == IEEE80211_CHAN_T)



#define BITNO_32(x) (((x) >> 16) ? 16 + BITNO_16((x) >> 16) : BITNO_16((x)))
#define BITNO_16(x) (((x) >> 8) ? 8 + BITNO_8((x) >> 8) : BITNO_8((x)))
#define BITNO_8(x) (((x) >> 4) ? 4 + BITNO_4((x) >> 4) : BITNO_4((x)))
#define BITNO_4(x) (((x) >> 2) ? 2 + BITNO_2((x) >> 2) : BITNO_2((x)))
#define BITNO_2(x) (((x) & 2) ? 1 : 0)
#define BIT(n)  (1 << n)



Laurin80211Frame::Laurin80211Frame()
{
	_radiotap = NULL;
	_frame = NULL;
	FrameLength = -1;
	FrameType = NOT_VALID;


	_source = (u_int8_t*) malloc(ETH_ALEN);
	_destination = (u_int8_t*) malloc(ETH_ALEN);
	_bssid = (u_int8_t*) malloc(ETH_ALEN);
}


Laurin80211Frame::Laurin80211Frame(const Laurin80211Frame& frame)
{
	_source = (u_int8_t*) malloc(ETH_ALEN);
	_destination = (u_int8_t*) malloc(ETH_ALEN);
	_bssid = (u_int8_t*) malloc(ETH_ALEN);

	memcpy(_source, frame._source, ETH_ALEN);
	memcpy(_destination, frame._destination, ETH_ALEN);
	memcpy(_bssid, frame._bssid, ETH_ALEN);

	FrameLength = frame.FrameLength;
	FrameType = frame.FrameType;

	_beacon_details = frame._beacon_details;
	_radio = frame._radio;
}


Laurin80211Frame::~Laurin80211Frame()
{
	free(_source);
	free(_destination);
	free(_bssid);

}


bool Laurin80211Frame::setFrame(const u_char* frame, int length)
{
	if(length <  sizeof(struct ieee80211_radiotap_header))
		return false;

	_radiotap = (struct ieee80211_radiotap_header*) frame;


	if(length < _radiotap->it_len + sizeof(laurin_ieee80211_hdr) || _radiotap->it_version)
		return false;

	_frame = &frame[_radiotap->it_len];
	FrameLength = length - _radiotap->it_len;

	return true;

}


bool Laurin80211Frame::parse80211Frame()
{
	if(!_frame)
		return false;

	laurin_ieee80211_hdr* header = (laurin_ieee80211_hdr*) _frame;

	int frame_type = WLAN_FC_GET_TYPE(header->frame_ctl);
	int frame_sub_type = WLAN_FC_GET_STYPE(header->frame_ctl);


	switch(frame_type)
	{

		// data
		case IEEE80211_FTYPE_DATA:
			if(frame_sub_type == IEEE80211_STYPE_DATA && (FrameLength >= IEEE80211_3ADDR_LEN ))
			{
				FrameType = DATA;
				return parse80211Header();
			}

			break;

		// ack / cts
		case IEEE80211_FTYPE_CTL:
			if((frame_sub_type & IEEE80211_STYPE_ACK) && (FrameLength >= IEEE80211_1ADDR_LEN ))
			{
				FrameType = ACK;
				return parse80211Header();
			}

			break;

		// beacon
		case IEEE80211_FTYPE_MGMT:

			// beacon has fixed parameters + tagged parameters. We check if it has at least the fixed parameters
			// and the ssid (first tagged parameters: 1 bytes for the index, and 1 byte for the length)
			if((frame_sub_type & IEEE80211_STYPE_BEACON) && (FrameLength >= IEEE80211_3ADDR_LEN + FIXED_PARAMETERS_OFFSET + 2))
			{
				FrameType = BEACON;
				return parse80211Header();
			}


			break;
	}

	return false;
}


bool Laurin80211Frame::parse80211Header()
{
	/*
	 * elaborate the 80211 header informations,
	 * in details, we get the bssid, source and destination address values.
	 * for doing so, we read the tods and fromds values and we act conseguently.
	 * we check if frame belongs to an ad-hoc network too. If so we return false.
	 *
	 *
	 * 		| from ds |  to ds 	|  description
	 * 		|---------|---------|-----------------------------------------------------------------------
	 * 	    |   0     |     0   |  ad-hoc network frame ( or not leaving DS),we don't support it!
	 * 		|   1     |     1   |  we are in the wireless distribution network
	 * 		|   1     |     0   |  from wired to wirelss frame (a frame from ds to a station via an AP)
	 * 		|   0     |     1   |  from wireless to wired frame (frame from station to DS via an AP)
	 *
	 */

	if(FrameType == ACK)
	{
		laurin_ieee80211_hdr_1addr* header = (laurin_ieee80211_hdr_1addr*) _frame;
		memcpy(_source, header->addr1, ETH_ALEN);
		memcpy(_destination, header->addr1, ETH_ALEN);
		memcpy(_bssid, header->addr1, ETH_ALEN);

	}
	else
	{

		laurin_ieee80211_hdr_3addr* header = (laurin_ieee80211_hdr_3addr*) _frame;

		//we have captured only a 3 address packet!
		if(WLAN_FC_GET_FROMDS(header->frame_ctl))
		{
			if(!(WLAN_FC_GET_TODS(header->frame_ctl)))
			{
				memcpy(_destination, header->addr1 , ETH_ALEN);
				memcpy(_bssid, header->addr2, ETH_ALEN);
				memcpy(_source, header->addr3, ETH_ALEN);
			}
			else
				return false;			// Not supported

		}
		else
		{

			if(WLAN_FC_GET_TODS(header->frame_ctl))
			{
				memcpy(_bssid, header->addr1, ETH_ALEN);
				memcpy(_source, header->addr2, ETH_ALEN);
				memcpy(_destination, header->addr3 , ETH_ALEN);
			}
			else
			{
				memcpy(_destination, header->addr1 , ETH_ALEN);
				memcpy(_source, header->addr2, ETH_ALEN);
				memcpy(_bssid, header->addr3, ETH_ALEN);
			}

		}

		// management frames are only the beacon ones
		if(FrameType == BEACON)
		{

			// skip the header and read the frame
			fixed_parameters* fp = (fixed_parameters*) &header->payload;
			_beacon_details.IBSSFrame = (fp->ibss == 1 && fp->ess == 0);
			_beacon_details.Interval = fp->beacon * 1024;			// beacon interval is expressed in unit of 1024 microseconds
			_beacon_details.Encrypted = fp->wep;


			// get tagged parameters (only ssid)
			u_char* tagged_para = (u_char*) &( (header->payload)[FIXED_PARAMETERS_OFFSET]);

			u_int8_t* ssid_len = (u_int8_t*) tagged_para + 1;       //skip the tag number

			if(*ssid_len <= 0 || (FrameLength < IEEE80211_3ADDR_LEN + FIXED_PARAMETERS_OFFSET + 2 + *ssid_len))
				return false;


			char* s = (char*) malloc(*ssid_len + 1);
			memcpy(s, tagged_para + 2 , *ssid_len);                 // plus 2 bytes

			s[*ssid_len] = '\0';

			_beacon_details.SSID = Glib::ustring(s);

			free(s);
		}
	}


	return true;

}


bool Laurin80211Frame::parseRadiotapHeader()
{
	/*
	 * - elaborate radio informations: antenna noise and signal etc...
	 * 	 we dissect the radiotap header, discarding all the informations that aren't necessary
	 *
	 * - most of the code is get from the kismet project (thanks!)
	 *
	 * - N.B we assume a little endian machine, no conversions are done
	 *   all the fields on the radiotap header are stored in little endian order.
	 *
	 * - I consider only ONE bitmap on the radiotap it_present field,
	 *   if there are more, I discard they. this is not a sniffer, so the informations that
	 *   can be stored on the supplementary bitmap extensions aren't necessary:
	 *   if these fields aren't commonly used,  I can't use they.
	 *
	 */


	if(!_radiotap)
		return false;


	u_int32_t present, next_present;
	u_int32_t* last_present;				// where last bitmap is, because after it there are stored the data.
	enum ieee80211_radiotap_type bit;
	u_char *iter = NULL;

	// I need to know where the bitmaps ends.
	for(last_present = &_radiotap->it_present; ((*last_present) & BIT(IEEE80211_RADIOTAP_EXT)) != 0 &&
		((u_char*)(last_present + sizeof(u_int32_t)) <= (u_char*) _radiotap + _radiotap->it_len); last_present += sizeof(u_int32_t));



	iter = (u_char*) last_present + sizeof(u_int32_t);
	u_int16_t bitmap, mhz;

	int check = 0;

	// read the bitmap
	for (present = _radiotap->it_present; present; present = next_present)
	{
		/* clear the least significant bit that is set */
		next_present = present & (present - 1);

		/* extract the least significant bit that is set */
		bit = (enum ieee80211_radiotap_type) BITNO_32(present ^ next_present);

		switch (bit)
		{

			case IEEE80211_RADIOTAP_FHSS:                           // The hop set and pattern for frequency-hopping radios.
			case IEEE80211_RADIOTAP_ANTENNA:                        // Unitless indication of the Rx/Tx antenna for this packet
			case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:          		// RF signal power at the antenna
			case IEEE80211_RADIOTAP_DBM_ANTNOISE:           		// RF noise power at the antenna
			case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
			case IEEE80211_RADIOTAP_DB_ANTNOISE:
			case IEEE80211_RADIOTAP_DBM_TX_POWER:           		// Transmit power expressed as dBm
				// these informations doesn't concern our purposes, so skip they
				iter = iter + sizeof(char);
				break;


			case IEEE80211_RADIOTAP_LOCK_QUALITY:           		// Quality of Barker code lock (Signal Quality)
			case IEEE80211_RADIOTAP_TX_ATTENUATION:         		// Transmit power expressed as unitless distance from max power set at factory calibration
			case IEEE80211_RADIOTAP_DB_TX_ATTENUATION:
				//skip
				iter = iter + sizeof(u_int16_t);
				break;


			case IEEE80211_RADIOTAP_FLAGS:                          // Properties of transmitted and received frames.
				_radio.flags = *((u_int8_t*) iter);
				iter = iter + sizeof(char);
				check++;

				break;

			case IEEE80211_RADIOTAP_RATE:                           // TX/RX data rate.
				_radio.rate = *((u_int8_t*) iter);
				iter = iter + sizeof(char);
				check++;

				break;


			case IEEE80211_RADIOTAP_CHANNEL:                        // Tx/Rx frequency in MHz, followed by flags.

				mhz = *((u_int16_t*)iter);
				iter = iter + sizeof(u_int16_t);

				bitmap = *((u_int16_t*)iter);

				_radio.channel = (short) ieee80211_mhz2ieee(mhz, bitmap);


				if (IEEE80211_IS_CHAN_FHSS(bitmap))
					_radio.carrier = CARRIER_80211FHSS;
				else if (IEEE80211_IS_CHAN_A(bitmap))
					_radio.carrier = CARRIER_80211A;
				else if (IEEE80211_IS_CHAN_B(bitmap))
					_radio.carrier = CARRIER_80211B;
				else if (IEEE80211_IS_CHAN_PUREG(bitmap))
					_radio.carrier = CARRIER_80211G;
				else if (IEEE80211_IS_CHAN_G(bitmap))
					_radio.carrier = CARRIER_80211G;
				else if (IEEE80211_IS_CHAN_T(bitmap))
					_radio.carrier = CARRIER_80211A;
				else
					_radio.carrier = CARRIER_UNKNOWN;

				iter = iter + sizeof(u_int16_t);
				check++;

				break;



			// Value in microseconds of the MAC's 64-bit 802.11 Time Synchronization Function timer
			// when the first bit of the MPDU arrived at the MAC
			case IEEE80211_RADIOTAP_TSFT:
				_radio.tstf = *((u_int64_t*) iter);
				iter = iter + sizeof(u_int64_t);
				check++;

				break;

			default:
				//  we can skip bit >= 14
				if(bit >= 14)
					continue;

				else
					return false;
		}
	}


	// necessary fields not present!
	return check == 4;
}


u_int8_t* Laurin80211Frame::getBSSIDAddress() const
{
	return _bssid;
}


u_int8_t* Laurin80211Frame::getSourceAddress() const
{
	return _source;
}


u_int8_t* Laurin80211Frame::getDestinationAddress() const
{
	return _destination;
}


LaurinBeaconDetails Laurin80211Frame::getBeaconDetails() const
{
	return _beacon_details;
}


LaurinPacketRadioInfo Laurin80211Frame::getRadioInformations() const
{
	return _radio;
}


bool Laurin80211Frame::operator <(const Laurin80211Frame& frame)
{
	return _radio.tstf < frame._radio.tstf;
}
